


#define  POINTER_TYPE(a) ((a*)NULL), __true_type()
#define  ENTITY_TYPE(a)  ((a*)NULL), __false_type()

#pragma warning( disable : 4786 )


#include <STRING>
#include <VECTOR>
#include <MAP>
#include "ISerial.h"
#include "type_traits.h"
#include <comutil.h>
#pragma warning (disable : 4267)

//#define GDEVOS_WINDOWS

using namespace std;

//typedef	signed		__int8		sint8;
//typedef	unsigned	__int8		uint8;
//typedef	signed		__int16		sint16;
//typedef	unsigned	__int16		uint16;
//typedef	signed		__int32		sint32;
//typedef	unsigned	__int32		uint32;
//typedef	signed		__int64		sint64;
//typedef	unsigned	__int64		uint64;
//typedef	unsigned 	int 		uint;
//typedef	signed 	    int 		sint;

#ifndef _ARCHIVE_ENTITY_H
#define _ARCHIVE_ENTITY_H

#define SERIAL_BASE_TYPE(t) inline void Serial(t& a)  { (m_pISerial->*m_SerialFunc)((&a), sizeof(t)); }

class CIArchive
{
public:
	enum 
	{
		R = 0,
		W = 1
	};
	// construct
	CIArchive(CISerial* pISerial, int mode)
	{
		m_pISerial   = pISerial;
		m_nMode      = mode;
		m_SerialFunc = (mode == R) ? &CISerial::Read : &CISerial::Write;
	}

	~CIArchive()
	{
	}

	bool IsReading()  { return (m_nMode == R); }

	template<class T> void Serial(T &obj) { TSerial(obj, __type_traits<T>::has_trivial_copy_constructor()); }
	template<class T> void TSerial(T &obj, __false_type) { obj.Serial(*this); }
	template<class T> void TSerial(T &obj, __true_type)  { (m_pISerial->*m_SerialFunc)(&obj, sizeof(T)); }

	template<class T, class T0>
	void Serial(vector<T>& vec, T0* t, __false_type)
	{
		if(IsReading())
		{
			unsigned short u2Len;		
			Serial(u2Len);
			
			for(int i = 0; i < u2Len; i++)
			{
				T t;
				Serial(t);
				vec.push_back(t);					
			}
		}
		else
		{
			unsigned short u2Len = vec.size();
			Serial(u2Len);

			for(int i = 0; i < u2Len; i++)
			{
				Serial((vec)[i]);
			}
		}
	}

	template<class T, class T0>
	void Serial(vector<T>& vec, T0* t, __true_type)
	{
		if(IsReading())
		{
			unsigned short u2Len;
			Serial(u2Len);

			for(int i = 0; i < u2Len; i++)
			{
				T0* t = new T0;
				Serial(*t);
				vec.push_back(t);					
			}
		}
		else
		{
			unsigned short  u2Len = vec.size();
			Serial(u2Len);

			for(int i = 0; i < u2Len; i++)
			{
				Serial(*(vec)[i]);
			}
		}
	}

	template<class K, class T, class T0>
	void Serial(map<K,T>& m, T0* t0, __true_type)
	{
		if(IsReading())
		{
			unsigned short u2Len;
			Serial(u2Len);

			K k;
			for(int i = 0; i < u2Len; i++)
			{
				Serial(k);				
				T0*	t = new T0;
				Serial(*t);
				m.insert(map<K,T>::value_type(k,t));						
			}
		}
		else
		{
			unsigned short u2Len = m.size();
			Serial(u2Len);

			map<K,T>::iterator s = m.begin();
			map<K,T>::iterator e = m.end();

			for(; s !=e; s++)
			{
				Serial((K)(s->first));
				Serial(*(s->second));
			}
		}
	}

	template<class K, class T, class T0>
	void Serial(map<K,T>& m, T0* t0, __false_type)
	{
		if(IsReading())
		{
			unsigned short u2Len;
			Serial(u2Len);
			
			K k;	
					
			for(int i = 0; i < u2Len; i++)
			{
				Serial(k);	
				
				T t;
				Serial(t);
				m.insert(map<K,T>::value_type(k,t));						
			}
		}
		else
		{
			unsigned short u2Len = m.size();
			Serial(u2Len);

			map<K,T>::iterator s = m.begin();
			map<K,T>::iterator e = m.end();

			for(; s !=e; s++)
			{
				Serial((K)(s->first));
				Serial((T)(s->second));
			}
		}
	}
	
	// base type
	//SERIAL_BASE_TYPE(char);
	//SERIAL_BASE_TYPE(int);
	//SERIAL_BASE_TYPE(long);
	//SERIAL_BASE_TYPE(short);

	//SERIAL_BASE_TYPE(unsigned char);
	//SERIAL_BASE_TYPE(UINT);
	//SERIAL_BASE_TYPE(unsigned long);
	//SERIAL_BASE_TYPE(unsigned short);

	//SERIAL_BASE_TYPE(float);
	//SERIAL_BASE_TYPE(double);
	SERIAL_BASE_TYPE( uint64 );


#ifdef _BYTE_DEFINED
	SERIAL_BASE_TYPE(BYTE);
#endif

#ifdef _WORD_DEFINED
	SERIAL_BASE_TYPE(WORD);
#endif

#ifdef _DWORD_DEFINED
	SERIAL_BASE_TYPE(DWORD);
#endif

#ifdef _LONG_DEFINED
	SERIAL_BASE_TYPE(LONG);
	SERIAL_BASE_TYPE(UINT);
	SERIAL_BASE_TYPE(BOOL);
#endif

	void Serial(string &a)
	{
		if(IsReading())
		{
			unsigned short u2Len;
			Serial(u2Len);
			
			if(m_pISerial->Size(CISerial::LEFT) >= (int)u2Len)
			{
				char* pBuf = new char[u2Len+1];
				(m_pISerial->*m_SerialFunc)(pBuf, u2Len);
				pBuf[u2Len] = '\0';
				a = string(pBuf);
				delete []pBuf;
			}
			else
			{
				(m_pISerial->*m_SerialFunc)(NULL, 0x0FFFFFFF);
			}
		}
		else
		{
			unsigned short u2Len = a.length();
			Serial(u2Len);
			(m_pISerial->*m_SerialFunc)((void*)a.c_str(), u2Len);
		}
	}
	
	void Serial(char* szBuf, int u2Size)
	{
		(m_pISerial->*m_SerialFunc)(szBuf, (int)u2Size);
	}
	
	// help function
	int Error()
	{
		return m_pISerial->Error();
	}

private:
	CISerial*   m_pISerial;
	SERIAL_FUNC m_SerialFunc;
	int         m_nMode;
};

#endif